home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / hobby / ast44src.zip / XCHARTS0.C < prev    next >
C/C++ Source or Header  |  1995-02-11  |  27KB  |  799 lines

  1. /*
  2. ** Astrolog (Version 4.40) File: xcharts0.c
  3. **
  4. ** IMPORTANT NOTICE: The graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1995 by Walter D. Pullen
  6. ** (astara@u.washington.edu). Permission is granted to freely use and
  7. ** distribute these routines provided one doesn't sell, restrict, or
  8. ** profit from them in any way. Modification is allowed provided these
  9. ** notices remain with any altered or edited versions of the program.
  10. **
  11. ** The main planetary calculation routines used in this program have
  12. ** been Copyrighted and the core of this program is basically a
  13. ** conversion to C of the routines created by James Neely as listed in
  14. ** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  15. ** available from Matrix Software. The copyright gives us permission to
  16. ** use the routines for personal use but not to sell them or profit from
  17. ** them in any way.
  18. **
  19. ** The PostScript code within the core graphics routines are programmed
  20. ** and Copyright (C) 1992-1993 by Brian D. Willoughby
  21. ** (brianw@sounds.wa.com). Conditions are identical to those above.
  22. **
  23. ** The extended accurate ephemeris databases and formulas are from the
  24. ** calculation routines in the program "Placalc" and are programmed and
  25. ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
  26. ** (alois@azur.ch). The use of that source code is subject to
  27. ** regulations made by Astrodienst Zurich, and the code is not in the
  28. ** public domain. This copyright notice must not be changed or removed
  29. ** by any user of this program.
  30. **
  31. ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
  32. ** X Window graphics initially programmed 10/23-29/1991.
  33. ** PostScript graphics initially programmed 11/29-30/1992.
  34. ** Last code change made 1/29/1995.
  35. */
  36.  
  37. #include "astrolog.h"
  38.  
  39.  
  40. #ifdef GRAPH
  41. /*
  42. ******************************************************************************
  43. ** Subchart Graphics Routines.
  44. ******************************************************************************
  45. */
  46.  
  47. /* Given a string, draw it on the screen using the given color. The       */
  48. /* position of the text is based the saved positions of where we drew the */
  49. /* text the last time the routine was called, being either directly below */
  50. /* in the same column or in the same row just to the right. This is used  */
  51. /* by the sidebar drawing routine to print a list of text on the chart.   */
  52.  
  53. int DrawPrint(sz, m, n)
  54. char *sz;
  55. int m, n;
  56. {
  57.   static int x0, x, y;
  58.  
  59.   if (sz == NULL) {    /* Null string means just initialize position. */
  60.     x0 = x = m; y = n;
  61.     return y;
  62.   }
  63.   if (y >= gs.yWin-1)  /* Don't draw if we've scrolled off the chart bottom. */
  64.     return y;
  65.   DrawColor(m);
  66.   DrawSz(sz, x, y, dtLeft | dtBottom);
  67.  
  68.   /* If the second parameter is TRUE, we stay on the same line, otherwise */
  69.   /* when FALSE we go to the next line at the original column setting.    */
  70.  
  71.   if (n)
  72.     x += CchSz(sz)*xFont*gi.nScaleT;
  73.   else {
  74.     x = x0;
  75.     n = y;
  76.     y += yFont*gi.nScaleT;
  77.   }
  78.   return y;
  79. }
  80.  
  81.  
  82. /* Print text showing the chart information and house and planet positions */
  83. /* of a chart in a "sidebar" to the right of the chart in question. This   */
  84. /* is always done for the -v and -w graphic wheel charts unless the -v0    */
  85. /* switch flag is also set, in which case none of the stuff here is done.  */
  86.  
  87. void DrawInfo()
  88. {
  89.   char sz[cchSzDef];
  90.   ET et;
  91.   int i, y, a, s;
  92.  
  93. #ifdef INTERPRET
  94.   int tot, abo, lef;
  95.  
  96.   /* Hack: Just for fun, if interpretation is active (which normally has  */
  97.   /* no effect whatsoever on graphics) we'll decorate the chart a little. */
  98.  
  99.   if (us.fInterpret) {
  100.     if (us.nScreenWidth & 1) {
  101.  
  102.       /* If screenwidth value is odd, draw a moire pattern in each corner. */
  103.  
  104.       abo = gs.yWin/(us.nScreenWidth/10);
  105.       lef = gs.xWin/(us.nScreenWidth/10);
  106.       for (y = 0; y <= 1; y++)
  107.         for (i = 0; i <= 1; i++)
  108.           for (s = 0; s <= 1; s++)
  109.             for (a = 1; a < (s ? lef : abo)*2; a++) {
  110.               DrawColor(a & 1 ? gi.kiGray : gi.kiOff);
  111.               DrawLine(i ? gs.xWin-1-lef : lef, y ? gs.yWin-1-abo : abo,
  112.                 s ? (i ? gs.xWin-1-a : a) : i*(gs.xWin-1),
  113.                 s ? y*(gs.yWin-1) : (y ? gs.yWin-1-a : a));
  114.             }
  115.     } else {
  116.  
  117.       /* If screenwidth is even, draw spider web lines in each corner. */
  118.  
  119.       DrawColor(gi.kiGray);
  120.       tot = us.nScreenWidth*3/20;
  121.       abo = gs.yWin/4;
  122.       lef = gs.xWin/4;
  123.       for (y = 0; y <= 1; y++)
  124.         for (i = 0; i <= 1; i++)
  125.           for (a = 1; a < tot; a++)
  126.             DrawLine(i*(gs.xWin-1), y ? (gs.yWin-1-a*abo/tot) : a*abo/tot,
  127.               i ? gs.xWin-1-lef+a*lef/tot : lef-a*lef/tot, y*(gs.yWin-1));
  128.     }
  129.   }
  130. #endif
  131.   if (!gs.fText || us.fVelocity)    /* Don't draw sidebar if */
  132.     return;                         /* -v0 flag is set.      */
  133.  
  134.   a = us.fAnsi;
  135.   us.fAnsi = -(!gs.fFont || (!gs.fMeta && !gs.fPS));
  136.   DrawColor(gi.kiLite);
  137.   if (gs.fBorder)
  138.     DrawLine(gs.xWin-1, 0, gs.xWin-1, gs.yWin-1);
  139.   gs.xWin += xSideT;
  140.   DrawPrint(NULL, gs.xWin-xSideT+xFontT-gi.nScaleT, yFont*7/5*gi.nScaleT);
  141.  
  142.   /* Print chart header and setting information. */
  143.   sprintf(sz, "%s %s", szAppName, szVersionCore);
  144.   DrawPrint(sz, gi.kiOn, fFalse);
  145.   if (*ciMain.nam)
  146.     DrawPrint(ciMain.nam, gi.kiLite, fFalse);
  147.   if (Mon == -1)
  148.     sprintf(sz, "No time or space.");
  149.   else if (us.nRel == rcComposite)
  150.     sprintf(sz, "Composite chart.");
  151.   else {
  152.     sprintf(sz, "%c%c%c %s", chDay3(DayOfWeek(Mon, Day, Yea)),
  153.       SzDate(Mon, Day, Yea, fTrue));
  154.     DrawPrint(sz, gi.kiLite, fFalse);
  155.     DrawPrint(SzTim(Tim), gi.kiLite, fTrue);
  156.     sprintf(sz, " (%cT %s GMT)", Dst != 0.0 ? 'D' : 'S', SzZone(Zon));
  157.   }
  158.   DrawPrint(sz, gi.kiLite, fFalse);
  159.   if (*ciMain.loc)
  160.     DrawPrint(ciMain.loc, gi.kiLite, fFalse);
  161.   DrawPrint(SzLocation(Lon, Lat), gi.kiLite, fFalse);
  162.   sprintf(sz, "%s houses.", szSystem[us.nHouseSystem]);
  163.   DrawPrint(sz, gi.kiLite, fFalse);
  164.   sprintf(sz, "%s, %s.", us.fSiderial ? "Sidereal" : "Tropical",
  165.     us.objCenter == 0 ? "Heliocentric" :
  166.     (us.objCenter == 1 ? "Geocentric" : szObjName[us.objCenter]));
  167.   DrawPrint(sz, gi.kiLite, fFalse);
  168.   sprintf(sz, "Julian Day = %11.4f", JulianDayFromTime(T));
  169.   DrawPrint(sz, gi.kiLite, fFalse);
  170.  
  171.   /* Print house cusp positions. */
  172.   DrawPrint("", gi.kiLite, fFalse);
  173.   for (i = 1; i <= cSign; i++) {
  174.     sprintf(sz, "%2d%s house: ", i, szSuffix[i]);
  175.     y = DrawPrint(sz, kSignB(i), fTrue);
  176.     if (!is.fSeconds && (gs.nScale == 100 ||
  177.       !gs.fFont || !gi.fFile || gs.fBitmap) && y < gs.yWin-1) {
  178.       s = gi.nScale;
  179.       gi.nScale = gi.nScaleT;
  180.       DrawSign(SFromZ(house[i]), gs.xWin-12*gi.nScaleT,
  181.         y-(yFont/2-1)*gi.nScaleT);
  182.       gi.nScale = s;
  183.     }
  184.     DrawPrint(SzZodiac(house[i]), kSignB(SFromZ(house[i])), fFalse);
  185.   }
  186.  
  187.   /* Print planet positions. */
  188.   DrawPrint("", gi.kiLite, fFalse);
  189.   for (i = 1; i <= oNorm; i++) if (!ignore[i] && !FCusp(i)) {
  190.     sprintf(sz, is.fSeconds ? "%3.3s: " : "%4.4s: ", szObjName[i]);
  191.     DrawPrint(sz, kObjB[i], fTrue);
  192.     y = DrawPrint(SzZodiac(planet[i]), kSignB(SFromZ(planet[i])), fTrue);
  193.     if (!is.fSeconds && i < starLo && (gs.nScale == 100 ||
  194.       !gs.fFont || !gi.fFile || gs.fBitmap) && y < gs.yWin-1) {
  195.       s = gi.nScale;
  196.       gi.nScale = gi.nScaleT;
  197.       DrawObject(i, gs.xWin-12*gi.nScaleT, y-(yFont/2-1)*gi.nScaleT);
  198.       gi.nScale = s;
  199.     }
  200.     sprintf(sz, "%c ", ret[i] < 0.0 ? chRet : ' ');
  201.     s = FThing(i);
  202.     DrawPrint(sz, gi.kiOn, s);
  203.     if (s) {
  204.       is.fSeconds = fFalse;
  205.       DrawPrint(SzAltitude(planetalt[i]), gi.kiLite, fFalse);
  206.       is.fSeconds = us.fSeconds;
  207.     }
  208.   }
  209.  
  210.   /* Print star positions. */
  211.   for (i = starLo; i <= starHi; i++) if (!ignore[i]) {
  212.     s = oNorm+starname[i-oNorm];
  213.     sprintf(sz, is.fSeconds ? "%3.3s: " : "%4.4s: ", szObjName[s]);
  214.     DrawPrint(sz, kObjB[s], fTrue);
  215.     DrawPrint(SzZodiac(planet[s]), kSignB(SFromZ(planet[s])), fTrue);
  216.     DrawPrint("  ", gi.kiOn, fTrue);
  217.     DrawPrint(SzAltitude(planetalt[s]), gi.kiLite, fFalse);
  218.   }
  219.  
  220.   /* Print element table information. */
  221.   DrawPrint("", gi.kiLite, fFalse);
  222.   CreateElemTable(&et);
  223.   sprintf(sz, "Fire: %d, Earth: %d,", et.coElem[eFir], et.coElem[eEar]);
  224.   DrawPrint(sz, gi.kiLite, fFalse);
  225.   sprintf(sz, "Air : %d, Water: %d", et.coElem[eAir], et.coElem[eWat]);
  226.   DrawPrint(sz, gi.kiLite, fFalse);
  227.   sprintf(sz, "Car: %d, Fix: %d, Mut: %d",
  228.     et.coMode[0], et.coMode[1], et.coMode[2]);
  229.   DrawPrint(sz, gi.kiLite, fFalse);
  230.   sprintf(sz, "Yang: %d, Yin: %d", et.coYang, et.coYin);
  231.   DrawPrint(sz, gi.kiLite, fFalse);
  232.   sprintf(sz, "M: %d, N: %d, A: %d, D: %d",
  233.     et.coMC, et.coIC, et.coAsc, et.coDes);
  234.   DrawPrint(sz, gi.kiLite, fFalse);
  235.   sprintf(sz, "Ang: %d, Suc: %d, Cad: %d",
  236.     et.coModeH[0], et.coModeH[1], et.coModeH[2]);
  237.   DrawPrint(sz, gi.kiLite, fFalse);
  238.   sprintf(sz, "Learn: %d, Share: %d", et.coLearn, et.coShare);
  239.   DrawPrint(sz, gi.kiLite, fFalse);
  240.   us.fAnsi = a;
  241. }
  242.  
  243.  
  244. /*
  245. ******************************************************************************
  246. ** Map Chart Routines.
  247. ******************************************************************************
  248. */
  249.  
  250. /* Another stream reader, this one is used by the globe drawing routine: */
  251. /* for the next body of land/water, return its name (and color), its     */
  252. /* longitude and latitude, and a vector description of its outline.      */
  253.  
  254. bool FReadWorldData(nam, loc, lin)
  255. char FAR **nam, FAR **loc, FAR **lin;
  256. {
  257.   static char FAR **psz = (char FAR **)szWorldData;
  258.   int i;
  259.  
  260.   *loc = *psz++;
  261.   *lin = *psz++;
  262.   *nam = *psz++;
  263.   if (*loc[0]) {
  264.     if (gs.fPrintMap && gi.fFile) {
  265.       i = **nam - '0';
  266.       AnsiColor(i ? kRainbowA[i] : kMainA[7]);
  267.       PrintSz(*nam+1); PrintL();
  268.     }
  269.     return fTrue;
  270.   }
  271.   psz = (char FAR **)szWorldData;  /* Reset stream when no data left. */
  272.   return fFalse;
  273. }
  274.  
  275.  
  276. /* Given longitude and latitude values on a globe, return the window        */
  277. /* coordinates corresponding to them. In other words, project the globe     */
  278. /* onto the view plane, and return where our coordinates got projected to,  */
  279. /* as well as whether our location is hidden on the back side of the globe. */
  280.  
  281. bool FGlobeCalc(x1, y1, u, v, cx, cy, rx, ry, deg)
  282. real x1, y1;
  283. int *u, *v, cx, cy, rx, ry, deg;
  284. {
  285.   real j, siny1;
  286.  
  287.   /* Compute coordinates for a general globe invoked with -XG switch. */
  288.  
  289.   if (gi.nMode == gGlobe) {
  290.     x1 = Mod(x1+(real)deg);    /* Shift by current globe rotation value. */
  291.     if (gs.rTilt != 0.0) {
  292.       /* Do another coordinate shift if the globe's equator is tilted any. */
  293.       x1 = RFromD(x1); y1 = RFromD(rDegQuad-y1);
  294.       CoorXform(&x1, &y1, RFromD(gs.rTilt));
  295.       x1 = Mod(DFromR(x1)); y1 = rDegQuad-DFromR(y1);
  296.     }
  297.     *v = cy + (int)((real)ry*-RCosD(y1)-rRound);
  298.     *u = cx + (int)((real)rx*-RCosD(x1)*RSinD(y1)-rRound);
  299.     return x1 > rDegHalf;
  300.   }
  301.  
  302.   /* Compute coordinates for a polar globe invoked with -XP switch. */
  303.  
  304.   siny1 = RSinD(y1);
  305.   j = gs.fAlt ? rDegQuad+x1+deg : 270.0-x1-deg;
  306.   *v = cy + (int)(siny1*(real)ry*RSinD(j)-rRound);
  307.   *u = cx + (int)(siny1*(real)rx*RCosD(j)-rRound);
  308.   return gs.fAlt ? y1 < rDegQuad : y1 > rDegQuad;
  309. }
  310.  
  311.  
  312. /* Draw one "Ley line" on the world map, based coordinates given in terms of */
  313. /* longitude and vertical fractional distance from the center of the earth.  */
  314.  
  315. void DrawLeyLine(l1, f1, l2, f2)
  316. real l1, f1, l2, f2;
  317. {
  318.   l1 = Mod(l1); l2 = Mod(l2);
  319.  
  320.   /* Convert vertical fractional distance to a corresponding coordinate. */
  321.  
  322.   f1 = rDegQuad-RAsin(f1)/rPiHalf*rDegQuad;
  323.   f2 = rDegQuad-RAsin(f2)/rPiHalf*rDegQuad;
  324.   DrawWrap((int)(l1*(real)gi.nScale+rRound)+1,
  325.            (int)(f1*(real)gi.nScale+rRound)+1,
  326.            (int)(l2*(real)gi.nScale+rRound)+1,
  327.            (int)(f2*(real)gi.nScale+rRound)+1, 1, gs.xWin-2);
  328. }
  329.  
  330.  
  331. /* Draw the main set of planetary Ley lines on the map of the world. This */
  332. /* consists of drawing an icosahedron and then a dodecahedron lattice.    */
  333.  
  334. void DrawLeyLines(deg)
  335. int deg;
  336. {
  337.   real off = (real)deg, phi, h, h1, h2, r, i;
  338.  
  339.   phi = (RSqr(5.0)+1.0)/2.0;                   /* Icosahedron constants. */
  340.   h = 1.0/(phi*2.0-1.0);
  341.   DrawColor(kMainB[6]);
  342.   for (i = off; i < rDegMax+off; i += 72.0) {  /* Draw icosahedron edges. */
  343.     DrawLeyLine(i, h, i+72.0, h);
  344.     DrawLeyLine(i-36.0, -h, i+36.0, -h);
  345.     DrawLeyLine(i, h, i, 1.0);
  346.     DrawLeyLine(i+36.0, -h, i+36.0, -1.0);
  347.     DrawLeyLine(i, h, i+36.0, -h);
  348.     DrawLeyLine(i, h, i-36.0, -h);
  349.   }
  350.   r = 1.0/RSqr(3.0)/phi/RCos(RFromD(54.0));    /* Dodecahedron constants. */
  351.   h2 = RSqr(1.0-r*r); h1 = h2/(phi*2.0+1.0);
  352.   DrawColor(kMainB[4]);
  353.   for (i = off; i < rDegMax+off; i += 72.0) {  /* Draw docecahedron edges. */
  354.     DrawLeyLine(i-36.0, h2, i+36.0, h2);
  355.     DrawLeyLine(i, -h2, i+72.0, -h2);
  356.     DrawLeyLine(i+36.0, h2, i+36.0, h1);
  357.     DrawLeyLine(i, -h2, i, -h1);
  358.     DrawLeyLine(i+36.0, h1, i+72.0, -h1);
  359.     DrawLeyLine(i+36.0, h1, i, -h1);
  360.   }
  361. }
  362.  
  363.  
  364. /* This major routine draws all of Astrolog's map charts. This means       */
  365. /* either the world map or the constellations, in either rectangular or    */
  366. /* globe hemisphere form. The rectangular chart may also be done in a      */
  367. /* Mollewide projection, for six total combinations. We shift the chart by */
  368. /* specified rotational and tilt values, and may draw on the chart each    */
  369. /* planet at its zenith position on Earth or location in constellations.   */
  370.  
  371. void DrawMap(fSky, fGlobe, deg)
  372. bool fSky, fGlobe;
  373. int deg;
  374. {
  375.   char *nam, *loc, *lin, chCmd;
  376.   int X[objMax], Y[objMax], M[objMax], N[objMax],
  377.     cx = gs.xWin/2, cy = gs.yWin/2, rx, ry, lon, lat, unit = 12*gi.nScale,
  378.     x, y, xold, yold, m, n, u, v, i, j, k, l, nScl = gi.nScale;
  379.   bool fNext = fTrue, fCan;
  380.   real planet1[objMax], planet2[objMax], x1, y1, rT;
  381. #ifdef CONSTEL
  382.   char *pch;
  383.   bool fBlank;
  384.   int isz = 0, nC, xT, yT, xDelta, yDelta, xLo, xHi, yLo, yHi;
  385. #endif
  386.  
  387.   /* Set up some variables. */
  388.   rx = cx-1; ry = cy-1;
  389.   if (fGlobe)
  390.     fCan = (gs.rTilt == 0.0 && gi.nMode != gPolar);
  391.  
  392. #ifdef CONSTEL
  393.   /* Draw a dot grid for large rectangular constellation charts. */
  394.   if (fSky && !fGlobe && !gs.fMollewide && gi.nScale/gi.nScaleT > 2)
  395.     for (yT = 5; yT < nDegHalf; yT += 5)
  396.       for (xT = 5; xT <= nDegMax; xT += 5) {
  397.         DrawColor(xT % 15 == 0 && yT % 10 == 0 ? gi.kiOn : gi.kiGray);
  398.         x = xT+deg;
  399.         if (x > nDegMax)
  400.           x -= nDegMax;
  401.         DrawPoint(x*nScl, yT*nScl);
  402.       }
  403. #endif
  404.  
  405.   loop {
  406.  
  407.     /* Get the next chunk of data to process. Get the starting position, */
  408.     /* map it to the screen, and set the drawing color appropriately.    */
  409.  
  410.     if (fNext) {
  411.       fNext = fFalse;
  412.  
  413.       /* For constellations, get data for the next constellation shape. */
  414.  
  415.       if (fSky) {
  416. #ifdef CONSTEL
  417.         isz++;
  418.         if (isz > cCnstl)
  419.           break;
  420.         DrawColor(gs.fAlt && gi.nMode != gPolar && (gi.nMode != gWorldMap ||
  421.           !gs.fMollewide) ? kMainB[7] : kRainbowB[6]);
  422.         pch = (char *)szDrawConstel[isz];
  423.         lon = nDegMax -
  424.           (((pch[2]-'0')*10+(pch[3]-'0'))*15+(pch[4]-'0')*10+(pch[5]-'0'));
  425.         lat = 90-((pch[6] == '-' ? -1 : 1)*((pch[7]-'0')*10+(pch[8]-'0')));
  426.         pch += 9;
  427.         xLo = xHi = xT = xold = x = lon;
  428.         yLo = yHi = yT = yold = y = lat;
  429.         nC = 0;
  430.         if (fGlobe) {
  431.           FGlobeCalc((real)x, (real)y, &m, &n, cx, cy, rx, ry, deg);
  432.           k = l = fTrue;
  433.         } else {
  434.           xold += deg;
  435.           x += deg;
  436.         }
  437. #else
  438.         ;
  439. #endif
  440.  
  441.       /* For world maps, get data for the next coastline piece. */
  442.  
  443.       } else {
  444.         if (!FReadWorldData(&nam, &loc, &lin))
  445.           break;
  446.         i = nam[0]-'0';
  447.         DrawColor((!fGlobe && gi.nMode == gAstroGraph) ? gi.kiOn :
  448.           (gi.nMode == gGlobe && gs.fAlt) ? gi.kiGray :
  449.           (i ? kRainbowB[i] : kMainB[7]));
  450.         lon = (loc[0] == '+' ? 1 : -1)*
  451.           ((loc[1]-'0')*100 + (loc[2]-'0')*10 + (loc[3]-'0'));
  452.         lat = (loc[4] == '+' ? 1 : -1)*((loc[5]-'0')*10 + (loc[6]-'0'));
  453.         if (fGlobe) {
  454.           x = 180-lon;
  455.           y = 90-lat;
  456.           FGlobeCalc((real)x, (real)y, &m, &n, cx, cy, rx, ry, deg);
  457.           k = l = fTrue;
  458.         } else {
  459.           xold = x = 181-lon+deg;
  460.           yold = y = 91-lat;
  461.         }
  462.       }
  463.     }
  464.  
  465.     /* Get the next unit from the string to draw on the screen as a line. */
  466.  
  467.     if (fSky) {
  468.  
  469.       /* For constellations we have a cache of how long we should keep    */
  470.       /* going in the previous direction, as say "u5" for up five should  */
  471.       /* move our pointer up five times without advancing string pointer. */
  472.  
  473. #ifdef CONSTEL
  474.       if (nC <= 0) {
  475.         if (!(chCmd = *pch)) {
  476.           fNext = fTrue;
  477.           if (gs.fText) {
  478.  
  479.             /* If we've reached the end of current constellation, compute */
  480.             /* the center location in it based on lower and upper bounds  */
  481.             /* we've maintained, and print the name of the constel there. */
  482.  
  483.             xT = xLo + (xHi - xLo)*(szDrawConstel[isz][0]-'1')/8;
  484.             yT = yLo + (yHi - yLo)*(szDrawConstel[isz][1]-'1')/8;
  485.             if (xT < 0)
  486.               xT += nDegMax;
  487.             else if (xT > nDegMax)
  488.               xT -= nDegMax;
  489.             if (fGlobe) {
  490.               if (FGlobeCalc((real)xT, (real)yT, &x, &y, cx, cy, rx, ry, deg))
  491.                 continue;
  492.             } else {
  493.               xT += deg;
  494.               if (xT > nDegMax)
  495.                 xT -= nDegMax;
  496.               if (gs.fMollewide)
  497.                 x = 180*nScl + NMultDiv(xT-180, NMollewide(yT-91), 180L);
  498.               else
  499.                 x = xT*nScl;
  500.               y = yT*nScl;
  501.             }
  502.             DrawColor(gs.fAlt && gi.nMode != gPolar && (gi.nMode !=
  503.               gWorldMap || !gs.fMollewide) ? gi.kiGray : kMainB[5]);
  504.             DrawSz(szCnstlAbbrev[isz], x, y, dtCent);
  505.           }
  506.           continue;
  507.         }
  508.         pch++;
  509.  
  510.         /* Get the next direction and distance from constellation string. */
  511.  
  512.         if (fBlank = (chCmd == 'b'))
  513.           chCmd = *pch++;
  514.         xDelta = yDelta = 0;
  515.         switch (chCmd) {
  516.         case 'u': yDelta = -1; break;    /* Up    */
  517.         case 'd': yDelta =  1; break;    /* Down  */
  518.         case 'l': xDelta = -1; break;    /* Left  */
  519.         case 'r': xDelta =  1; break;    /* Right */
  520.         case 'U': yDelta = -1; nC = (yT-1)%10+1;    break;  /* Up until    */
  521.         case 'D': yDelta =  1; nC = 10-yT%10;       break;  /* Down until  */
  522.         case 'L': xDelta = -1; nC = (xT+599)%15+1;  break;  /* Left until  */
  523.         case 'R': xDelta =  1; nC = 15-(xT+600)%15; break;  /* Right until */
  524.         default: PrintError("Bad draw.");             /* Shouldn't happen. */
  525.         }
  526.         if (chCmd >= 'a')
  527.           nC = NFromPch(&pch);    /* Figure out how far to draw. */
  528.       }
  529.       nC--;
  530.       xT += xDelta; x += xDelta;
  531.       yT += yDelta; y += yDelta;
  532.       if (fBlank) {
  533.         xold = x; yold = y;    /* We occasionally want to move the pointer */
  534.         l = fFalse;            /* without drawing the line on the screen.  */
  535.         continue;
  536.       }
  537.       if (xT < xLo)         /* Maintain our bounding rectangle for this */
  538.         xLo = xT;           /* constellation if we crossed over it any. */
  539.       else if (xT > xHi)
  540.         xHi = xT;
  541.       if (yT < yLo)
  542.         yLo = yT;
  543.       else if (yT > yHi)
  544.         yHi = yT;
  545. #else
  546.       ;
  547. #endif
  548.  
  549.     } else {
  550.  
  551.       /* Get the next unit from the much simpler world map strings. */
  552.  
  553.       if (!(chCmd = *lin)) {
  554.         fNext = fTrue;
  555.         continue;
  556.       }
  557.       lin++;
  558.  
  559.       /* Each unit is exactly one character in the coastline string. */
  560.  
  561.       if (chCmd == 'L' || chCmd == 'H' || chCmd == 'G')
  562.         x--;
  563.       else if (chCmd == 'R' || chCmd == 'E' || chCmd == 'F')
  564.         x++;
  565.       if (chCmd == 'U' || chCmd == 'H' || chCmd == 'E')
  566.         y--;
  567.       else if (chCmd == 'D' || chCmd == 'G' || chCmd == 'F')
  568.         y++;
  569.     }
  570.  
  571.     /* Transform map coordinates to screen coordinates and draw a line. */
  572.  
  573.     while (x >= nDegMax)    /* Take care of coordinate wrap around. */
  574.       x -= nDegMax;
  575.     while (x < 0)
  576.       x += nDegMax;
  577.     if (abs(x-xold) > nDegHalf)
  578.       xold = x;
  579.  
  580.     if (fGlobe) {
  581.  
  582.       /* For globes, we have to go do a complicated transformation, and not */
  583.       /* draw when we're hidden on the back side of the sphere. We're smart */
  584.       /* and try to only do the slow stuff when we know we'll be visible.   */
  585.  
  586.       if (fCan) {
  587.         k = x+deg;
  588.         if (k >= nDegMax)
  589.           k -= nDegMax;
  590.         k = (k <= 180);
  591.       }
  592.       if (k && !FGlobeCalc((real)x, (real)y, &u, &v, cx, cy, rx, ry, deg)) {
  593.         if (l)
  594.           DrawLine(m, n, u, v);
  595.         m = u; n = v;
  596.         l = fTrue;
  597.       } else
  598.         l = fFalse;
  599.     } else {
  600.  
  601.       /* Rectangular maps are much simpler, with screen coordinates      */
  602.       /* proportional to internal coords. For the Mollewide projection   */
  603.       /* we have to apply a factor to the horizontal positioning though. */
  604.  
  605.       if (gs.fMollewide && gi.nMode != gAstroGraph)
  606.         DrawLine(180*nScl + NMultDiv(xold-180,
  607.           NMollewide(yold-91), 180L), yold*nScl,
  608.           180*nScl + NMultDiv(x-180, NMollewide(y-91), 180L), y*nScl);
  609.       else
  610.         DrawLine(xold*nScl, yold*nScl, x*nScl, y*nScl);
  611.       xold = x; yold = y;
  612.     }
  613.   }
  614.  
  615.   /* Draw the outline of the map, either a circle around globes or a */
  616.   /* Mollewide type ellipse for that type of rectangular chart.      */
  617.  
  618.   DrawColor(gi.kiOn);
  619.   if (!fGlobe) {
  620.     if (gs.fMollewide && gi.nMode != gAstroGraph)
  621.       if (!gs.fAlt)
  622.         for (xold = 0, y = -89; y <= 90; y++, xold = x)
  623.           for (x = NMollewide(y), i = -1; i <= 1; i += 2)
  624.             {
  625.             DrawLine(180*nScl + i*xold - (i == 1), (90+y)*nScl,
  626.               180*nScl + i*x - (i == 1), (91+y)*nScl);
  627.             }
  628.   } else
  629.     DrawEllipse(0, 0, gs.xWin-1, gs.yWin-1);
  630.  
  631.   /* Now, if we are in an appropriate bonus chart mode, draw each planet at */
  632.   /* its zenith or visible location on the globe or map, if not hidden.     */
  633.  
  634.   if (!gs.fAlt || (gi.nMode != gGlobe &&
  635.     (!fSky || gi.nMode != gWorldMap || gs.fMollewide)))
  636.     return;
  637.   rT = gs.fConstel ? rDegHalf - (fGlobe ? 0.0 : (real)deg) : Lon;
  638.   if (rT < 0.0)
  639.     rT += rDegMax;
  640.   for (i = 1; i <= cObj; i++) {
  641.     planet1[i] = RFromD(Tropical(planet[i]));
  642.     planet2[i] = RFromD(planetalt[i]);
  643.     EclToEqu(&planet1[i], &planet2[i]);    /* Calculate zenith long. & lat. */
  644.   }
  645.  
  646.   /* Compute screen coordinates of each object, if it's even visible. */
  647.  
  648.   for (i = 1; i <= cObj; i++) if (FProper(i)) {
  649.     if (fSky)
  650.       x1 = planet1[i];
  651.     else
  652.       x1 = planet1[oMC]-planet1[i];
  653.     if (x1 < 0.0)
  654.       x1 += 2.0*rPi;
  655.     if (x1 > rPi)
  656.       x1 -= 2.0*rPi;
  657.     x1 = Mod(rDegHalf-rT-DFromR(x1));
  658.     y1 = rDegQuad-DFromR(planet2[i]);
  659.     if (fGlobe) {
  660.       X[i] = FGlobeCalc(x1, y1, &u, &v, cx, cy, rx, ry, deg) ? -1000 : u;
  661.       Y[i] = v;
  662.     } else {
  663.       X[i] = (int)(x1 * (real)nScl);
  664.       Y[i] = (int)(y1 * (real)nScl);
  665.     }
  666.     M[i] = X[i]; N[i] = Y[i]+unit/2;
  667.   }
  668.  
  669.   /* Now that we have the coordinates of each object, figure out where to   */
  670.   /* draw the glyphs. Again we try not to draw glyphs on top of each other. */
  671.  
  672.   for (i = 1; i <= cObj; i++) if (FProper(i)) {
  673.     k = l = gs.xWin+gs.yWin;
  674.  
  675.     /* For each planet, we draw the glyph either right over or right under */
  676.     /* the actual zenith location point. So, find out the closest distance */
  677.     /* of any other planet assuming we place ours at both possibilities.   */
  678.  
  679.     for (j = 1; j < i; j++) if (FProper(j)) {
  680.       k = Min(k, abs(M[i]-M[j])+abs(N[i]-N[j]));
  681.       l = Min(l, abs(M[i]-M[j])+abs(N[i]-unit-N[j]));
  682.     }
  683.  
  684.     /* Normally, we put the glyph right below the actual point. If however  */
  685.     /* another planet is close enough to have their glyphs overlap, and the */
  686.     /* above location is better, then we'll draw the glyph above instead.   */
  687.  
  688.     if (k < unit || l < unit)
  689.       if (k < l)
  690.         N[i] -= unit;
  691.   }
  692.   for (i = cObj; i >= 1; i--) if (X[i] >= 0 && FProper(i))      /* Draw the */
  693.     DrawObject(i, M[i], N[i]);                                  /* glyphs.  */
  694.   for (i = cObj; i >= 1; i--) if (X[i] >= 0 && FProper(i)) {
  695.     DrawColor(kObjB[i]);
  696.     DrawSpot(X[i], Y[i]);
  697.   }
  698. }
  699.  
  700.  
  701. /* Create a chart in the window based on the current graphics chart mode. */
  702. /* This is the main dispatch routine for all of the program's graphics.   */
  703.  
  704. void DrawChartX()
  705. {
  706.   char sz[cchSzDef];
  707.   int i;
  708.   bool fT;
  709.  
  710.   gi.nScale = gs.nScale/100;
  711.  
  712.   if (gs.fBitmap || gs.fMeta)
  713.     PrintNotice("Creating graphics chart in memory.");
  714.   DrawClearScreen();
  715. #ifdef CONSTEL
  716.   fT = gs.fConstel;
  717. #else
  718.   fT = fFalse;
  719. #endif
  720.   switch (gi.nMode) {
  721.   case gWheel:
  722.   case gHouse:
  723.     if (us.nRel > rcDual)
  724.       XChartWheel();
  725.     else
  726.       XChartWheelRelation();
  727.     break;
  728.   case gGrid:
  729.     if (us.nRel > rcDual)
  730.       XChartGrid();
  731.     else
  732.       XChartGridRelation();
  733.     break;
  734.   case gHorizon:
  735.     if (us.fPrimeVert)
  736.       XChartHorizonSky();
  737.     else
  738.       XChartHorizon();
  739.     break;
  740.   case gOrbit:
  741.     XChartOrbit();
  742.     break;
  743.   case gDisposit:
  744.     XChartDispositor();
  745.     break;
  746.   case gAstroGraph:
  747.     DrawMap(fFalse, fFalse, gs.nRot);  /* First draw map of world.           */
  748.     XChartAstroGraph();                /* Then draw astro-graph lines on it. */
  749.     break;
  750.   case gCalendar:
  751.     XChartCalendar();
  752.     break;
  753.   case gEphemeris:
  754.     XChartEphemeris();
  755.     break;
  756.   case gWorldMap:
  757.     DrawMap(fT, fFalse, gs.nRot);           /* First draw map of world. */
  758.     if (!fT && gs.fAlt && !gs.fMollewide)   /* Then maybe Ley lines.    */
  759.       DrawLeyLines(gs.nRot);
  760.     break;
  761.   case gGlobe:
  762.   case gPolar:
  763.     DrawMap(fT, fTrue, gs.nRot);
  764.     break;
  765. #ifdef BIORHYTHM
  766.   case gBiorhythm:
  767.     XChartBiorhythm();
  768.     break;
  769. #endif
  770.   }
  771.  
  772.   /* Print text showing chart information at bottom of window. */
  773.  
  774.   DrawColor(gi.kiLite);
  775.   if (fDrawText) {
  776.     if (Mon == -1)
  777.       sprintf(sz, "(No time or space)");
  778.     else if (us.nRel == rcComposite)
  779.       sprintf(sz, "(Composite)");
  780.     else {
  781.       fT = us.fAnsi; us.fAnsi = -(!gs.fFont || (!gs.fMeta && !gs.fPS));
  782.       i = DayOfWeek(Mon, Day, Yea);
  783.       sprintf(sz, "%c%c%c %s %s (%cT %s GMT) %s", chDay3(i),
  784.         SzDate(Mon, Day, Yea, 2), SzTim(Tim), Dst != 0.0 ? 'D' : 'S',
  785.         SzZone(Zon), SzLocation(Lon, Lat));
  786.       us.fAnsi = fT;
  787.     }
  788.     DrawSz(sz, gs.xWin/2, gs.yWin-3*gi.nScaleT, dtBottom | dtErase);
  789.   }
  790.  
  791.   /* Draw a border around the chart if the mode is set and appropriate. */
  792.  
  793.   if (fDrawBorder)
  794.     DrawEdgeAll();
  795. }
  796. #endif /* GRAPH */
  797.  
  798. /* xcharts0.c */
  799.